`timescale 1ns/1ps
`default_nettype none
// 文件名称: rtl/controller.v
// 作用：指令译码控制（RV32I ）
module controller(
    input  wire [31:0] instr,
    output wire        regwrite,
    output wire        alusrc_b,
    output wire [3:0]  alu_ctrl,
    output wire        memread,
    output wire        memwrite,
    output wire        memtoreg,
    output wire        jal,
    output wire        branch,
    output wire        jalr,        // ★ 新增：JALR 标志
    output wire [2:0]  branch_type,
    output wire [1:0]  alu_src_a_sel,
    output wire [1:0]  load_size,
    output wire        load_unsigned,
    output wire [1:0]  store_size,
    output wire        use_imm_u,
    // 新增输出
    output wire        is_csr,        // 本条是 CSR 指令
    output wire [2:0]  csr_funct3,    // 001/010/011/101/110/111
    output wire [11:0] csr_addr,      // instr[31:20]
    output wire        is_ecall,      // SYSTEM + imm12=0
    output wire        is_mret       // SYSTEM + imm12=0x302
);
    // 基本字段
    wire [6:0] opcode = instr[6:0];
    wire [2:0] funct3 = instr[14:12];
    wire [6:0] funct7 = instr[31:25];
    wire [11:0] imm12 = instr[31:20];

    // opcode
    localparam OP_IMM = 7'b0010011;  // I-imm   (ADDI/SLTI/SLTIU/XORI/ORI/ANDI/SLLI/SRLI/SRAI)
    localparam OP     = 7'b0110011;  // R       (ADD/SUB/...)
    localparam LOAD   = 7'b0000011;  // Loads   (LB/LH/LW/LBU/LHU)
    localparam STORE  = 7'b0100011;  // Stores  (SB/SH/SW)
    localparam BRANCH = 7'b1100011;  // Branch  (BEQ/BNE/BLT/BGE/BLTU/BGEU)
    localparam LUI    = 7'b0110111;  // LUI
    localparam AUIPC  = 7'b0010111;  // AUIPC
    localparam JAL    = 7'b1101111;  // JAL
    localparam JALR   = 7'b1100111;  // JALR
    localparam SYSTEM = 7'b1110011;  // SYSTEM (CSR/ECALL/EBREAK/MRET/…)
    localparam MISC_MEM = 7'b0001111;// FENCE/FENCE.I

    // 类型
    wire is_opimm = (opcode==OP_IMM);
    wire is_op    = (opcode==OP);
    wire is_load  = (opcode==LOAD);
    wire is_store = (opcode==STORE);
    wire is_branch= (opcode==BRANCH);
    wire is_lui   = (opcode==LUI);
    wire is_auipc = (opcode==AUIPC);
    wire is_jal   = (opcode==JAL);
    wire is_jalr  = (opcode==JALR) && (funct3==3'b000);
    wire is_system  = (opcode==SYSTEM);
    wire is_miscmem = (opcode==MISC_MEM); // FENCE / FENCE.I -> NOP

    // ---------------- CSR / Trap 识别 ----------------
    // SYSTEM + funct3==000 ：特殊/陷阱类（ECALL/EBREAK/MRET 等，由 imm12 区分）
    // SYSTEM + funct3!=000 ：CSR 指令（CSRRW/RS/RC 及 *I 变体）
    assign is_ecall = is_system && (funct3==3'b000) && (imm12==12'h000);
    assign is_mret  = is_system && (funct3==3'b000) && (imm12==12'h302);

    assign is_csr   = is_system && (funct3!=3'b000);
    assign csr_funct3 = funct3;
    assign csr_addr   = instr[31:20];

    // OP-IMM / OP 具体功能（只决定 alu_ctrl）
    // OP-IMM: funct3=000 ADDI, 010 SLTI, 011 SLTIU, 100 XORI, 110 ORI, 111 ANDI,
    //         001 SLLI(funct7=0000000), 101 SRLI(f7=0000000)/SRAI(f7=0100000)
    // OP:     funct3=000 ADD/SUB(f7=0000000/0100000), 001 SLL, 010 SLT, 011 SLTU,
    //         100 XOR, 101 SRL/SRA, 110 OR, 111 AND
    reg [3:0] alu_sel;
    always @* begin
        alu_sel = 4'b0000; // default ADD
        if (is_opimm) begin
            case (funct3)
                3'b000: alu_sel = 4'b0000;                       // ADDI
                3'b010: alu_sel = 4'b0011;                       // SLTI
                3'b011: alu_sel = 4'b0100;                       // SLTIU
                3'b100: alu_sel = 4'b0101;                       // XORI
                3'b110: alu_sel = 4'b1000;                       // ORI
                3'b111: alu_sel = 4'b1001;                       // ANDI
                3'b001: alu_sel = 4'b0010;                       // SLLI (f7=0000000)
                3'b101: alu_sel = (funct7==7'b0100000) ? 4'b0111 // SRAI
                                                       : 4'b0110; // SRLI
            endcase
        end else if (is_op) begin
            case (funct3)
                3'b000: alu_sel = (funct7==7'b0100000) ? 4'b0001 : 4'b0000; // SUB/ADD
                3'b001: alu_sel = 4'b0010;                                   // SLL
                3'b010: alu_sel = 4'b0011;                                   // SLT
                3'b011: alu_sel = 4'b0100;                                   // SLTU
                3'b100: alu_sel = 4'b0101;                                   // XOR
                3'b101: alu_sel = (funct7==7'b0100000) ? 4'b0111 : 4'b0110; // SRA/SRL
                3'b110: alu_sel = 4'b1000;                                   // OR
                3'b111: alu_sel = 4'b1001;                                   // AND
            endcase
        end else if (is_lui || is_auipc) begin
            alu_sel = 4'b0000; // 0 + imm_u 或 pc + imm_u
        end else begin
            alu_sel = 4'b0000; // 其他情况默认 ADD（例如地址计算/分支目标在上游处理）
        end
    end
    assign alu_ctrl = alu_sel;

    // 分支类型编码（给 EX 判定）
    // 000=BEQ 001=BNE 010=BLT 011=BGE 100=BLTU 101=BGEU
    reg [2:0] brtype;
    always @* begin
        brtype = 3'b000;
        if (is_branch) begin
            case (funct3)
                3'b000: brtype = 3'b000; // BEQ
                3'b001: brtype = 3'b001; // BNE
                3'b100: brtype = 3'b010; // BLT
                3'b101: brtype = 3'b011; // BGE
                3'b110: brtype = 3'b100; // BLTU
                3'b111: brtype = 3'b101; // BGEU
                default: brtype = 3'b000;
            endcase
        end
    end
    assign branch_type = brtype;

    // ALU A 源选择：LUI=zero, AUIPC=pc, 其他=rs1
    assign alu_src_a_sel =
        is_lui   ? 2'b10 :
        is_auipc ? 2'b01 :
                   2'b00 ; // 默认 rs1

    // ALU B 源选择：使用立即数的指令：OP-IMM/Loads/Stores/LUI/AUIPC/JALR 地址计算
    assign alusrc_b = is_opimm | is_load | is_store | is_lui | is_auipc | is_jalr;

    // 访存控制
    assign memread  = is_load;
    assign memwrite = is_store;
    assign memtoreg = is_load;

    // Jumps / Branch
    assign jal    = is_jal;
    assign jalr   = is_jalr;
    assign branch = is_branch;

    // U-型立即数使用（供上游 imm 选择用：LUI/AUIPC）
    assign use_imm_u = is_lui | is_auipc;

    // Load 大小与无符号
    // funct3: LB=000 LH=001 LW=010 LBU=100 LHU=101
    reg [1:0] lsize; reg luns;
    always @* begin
        lsize = 2'b10; // 默认字
        luns  = 1'b0;  // 默认有符号
        if (is_load) begin
            case (funct3)
                3'b000: begin lsize=2'b00; luns=1'b0; end // LB
                3'b001: begin lsize=2'b01; luns=1'b0; end // LH
                3'b010: begin lsize=2'b10; luns=1'b0; end // LW
                3'b100: begin lsize=2'b00; luns=1'b1; end // LBU
                3'b101: begin lsize=2'b01; luns=1'b1; end // LHU
                default:begin lsize=2'b10; luns=1'b0; end
            endcase
        end
    end
    assign load_size     = lsize;
    assign load_unsigned = luns;

    // Store 大小
    // funct3: SB=000 SH=001 SW=010
    reg [1:0] ssize;
    always @* begin
        ssize = 2'b10; // 默认字
        if (is_store) begin
            case (funct3)
                3'b000: ssize = 2'b00; // SB
                3'b001: ssize = 2'b01; // SH
                3'b010: ssize = 2'b10; // SW
                default:ssize = 2'b10;
            endcase
        end
    end
    assign store_size = ssize;

    // 写回寄存器：所有算术/逻辑/立即数/Load/JAL/JALR/LUI/AUIPC 都写回
    wire regwrite_core =
           is_opimm | is_op | is_load | is_jal | is_jalr | is_lui | is_auipc;
    assign regwrite = regwrite_core | is_csr;
endmodule
